-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scorekeeper Refactoring 1/4 #2934
base: staging
Are you sure you want to change the base?
Conversation
@@ -235,6 +219,14 @@ export default class ScoreKeeper { | |||
return true; | |||
} | |||
|
|||
startJobs(metadata: JobRunnerMetadata) { | |||
this._jobs = jobConfigs.map((config) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a way to control which job to start, instead of all of them ? good for local testing purposes
With the JobFactory you could control that by commenting out the specif job you didn't want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best would be to control the jobs from the config. For example, with isActive
flag.
As for the JobFactory
, with the current change, you can comment lines related to a particular JobConfig
and achieve the same result. But of course, it's not how it should be in the first place. Config or env variables is the way to go.
// {
// jobKey: "validity",
// defaultFrequency: Constants.VALIDITY_CRON,
// jobFunction: validityJobWithTiming,
// name: JobNames.Validity,
// },
{
jobKey: "score",
defaultFrequency: Constants.SCORE_CRON,
jobFunction: scoreJobWithTiming,
name: JobNames.Score,
},
| "finished" | ||
| "errored" | ||
| "started" | ||
| "Not Running"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why Not Running
starts with capital letters ?
They should probably be constants/enum defined somewhere rather than hardcoded strings, wdyt ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100% agree, that's the plan.
I commented, There is a dependency on status names in scorekeeper-status-ui
. I decided not to touch it just to minimize the impact of the current PR. Also, I need to check if more dependencies on this status name exist.
this.status = { | ||
name: jobConfig.name, | ||
updated: Date.now(), | ||
status: "Not Running", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be of type StatusName, right ? can we avoid to have the string Not Running
hardcoded ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I partially answered in the previous comment. Please let me know if you want me to include this in the current PR.
For the renaming issue, there is a dependency at least on scorekeeper-status-ui
.
For the hardcoding issue, it's easier, but the plan was to tackle it together.
}; | ||
export const jobConfigs: JobConfig[] = [ | ||
{ | ||
jobKey: "activeValidator", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it make sense to have these jobKeys defined as constants or enums instead of hardcoded strings ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it absolutely makes sense. This question also related to the default cron strings, which are located in the constants.
Current state:
- Config holds information about both job keys and cron strings.
- Source code also holds information about the job keys and default cron strings. The source code assumes the config could be not valid or not full.
The question is - why do we have defaults for the cron strings? If we trust the config, then we should have only one source of truth.
I suggest:
- Add an Enum containing all of the Job names (
jobKey
). It would be our source of truth. - Validate the config structure (contains all jobs keys, cron string, isActive flag, etc.).
- Remove default cron strings from the source code.
This way we'd also simplify JobConfig
type.
Instead of this👇 we'd need only mapping between jobKey
and jobFunction
:
{
jobKey: "activeValidator",
defaultFrequency: Constants.ACTIVE_VALIDATOR_CRON,
jobFunction: activeValidatorJobWithTiming,
name: JobNames.ActiveValidator,
},
Alternatively, we can leave default cron strings at the source code level. But store them closer to the Enum of job names or even in the same structure.
WDYT?
@@ -1,83 +0,0 @@ | |||
import { logger } from "../..//index"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the idea is to nuke everything related to the Microservice version, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the idea of decoupling from the Gateway is still relevant. Implementing with bullmq
is one option. BTW even with the queue implementation, I see no usage for that class. All the jobs would be initialized on the worker side and the worker becomes the new Scorekeeper in that case.
However, a simpler approach would be to leave everything as is and only change the job status handling. By persisting the job status in the DB and removing events, we can achieve similar results and decouple Scorekeeper from API. That's what I suggest.
Moving from this:
await createServer(config, handler, scorekeeper);
To this:
await createServer(config, handler);
This way API could get the job statuses directly from the DB and there would be no need to run everything tightly coupled.
Question: the scorekeeper is currently part of the common package. Is it really common or it deserves to have its own package ? wdyt ? |
It looks like Answering the question. It's already a separate package but with a weird name and locality/structure issues. What we can/should do is to make it work on its own. At the moment one of the responsibilities of the Scorekeeper class is to expose a public interface for the API (Gateway): https://github.com/w3f/1k-validators-be/blob/master/packages/gateway/src/routes/setupRoutes.ts#L69-L76 By removing this dependency we can run it on its own: in a separate process/container. @ironoa Does it make sense to you? |
This pull request initiates the refactoring of the Scorekeeper and Gateway components. The goal of this refactoring is to simplify the codebase, reduce technical debt, and improve maintainability and scalability. This is the first stage of a multi-step process to achieve a cleaner and more modular architecture.
Problems:
Job
class has several injections, such asRegisterHandler
andcron/StartCronJobs/startJob
, causing locality issues.MonolithJobRunner
,MicroserviceJobRunner
,JobsRunnerFactory
,JobsRunner
,JobFactory
, and individual classes for each job.MicroserviceJobRunner
is particularly problematic.Final goal of the Scorekeeper refactoring:
Job
class. The state will be represented by the DB layer only.JobConfig
toJob
class instance tojob.start()
.Current PR changes:
JobNames
enum will be removed in a future update.Job
class.Job
class, supports the old public interfaces, and explicitly shows dependency injection for thestartJobFunction
, which will be removed later.metadata
parameter, even if it's not used.Job
class.Potential next steps (to be discussed):
Job
class. RemoveJobNames
enum. Scorekeeper Refactoring 2/4 #2937onlyHealth
flag).